/*****************************************************************************
*    Ali Corp. All Rights Reserved. 2002 Copyright (C)
*
*    File:    bootloader.c
*
*    Description:    This file contains all globe micros and functions declare
*                    of Flash boot loader.
*    History:
*           Date            Athor        Version          Reason
*       ============    =============   =========   =================
*   1.  Oct.28.2003     Justin Wu       Ver 0.1    Create file.
 *  2.  2006.5.16       Justin Wu       Ver 0.2    STO chunk support & clean up.
*****************************************************************************/
#include "bootloader.h"


extern void __SEE_ROM_START();
extern void __SEE_ROM_END();

UINT32 g_boot_type = 0;             /* 0--Nor, 1--Nand, 2--SDIO, 3--EMMC, 9--Unknow */

#ifdef _PMU_STANDBY_ENABLE_     
static void Cold_Pmu_Enter_Standby(UINT8       boot_type)
{
	if((boot_type & BOOT_TYPE_MASK) && (GET_BYTE(PMU_BASE+EXIT_STANDBY_STATUS)==0))
	{
		unsigned int nec_ir_key = 0x60df708f;// 0x60dfc837/0x60dfc837;
		unsigned char ir_type  = 0;
		pmu_m36_attach(NULL , NULL);
		pmu_m36_ir_init();
		PMU_Key_Transfrom(nec_ir_key,ir_type);

		if((ALI_S3821==sys_ic_get_chip_id()) && (sys_ic_get_rev_id() == IC_REV_1))
		{
			*(volatile unsigned char *)(0xb805c05f) = 0;
		}

		/*Panel show OFF*/
		*(volatile unsigned char *)(0xb8053ffe) = 0;
		*(volatile unsigned char *)(0xb8053fff) = 1;

		/*copy MCU code into PMU SRAM*/
		*(volatile unsigned int *)0xb8000084 |=1<<25;   
		*(volatile unsigned int *)0xb805d100&=~(1<<0);  //ram switch
		MEMCPY(0xb8050000, g_ali_pmu_bin, sizeof(g_ali_pmu_bin)/sizeof(UINT8));

		*(volatile unsigned int *)0xb8000084 &=~(1<<25);//reset MCU
		
		pmu_m36_en();//enter pmu stanby
	}	
}
#endif

static void bl_dump_data(UINT8 *data, UINT32 len)
{
#if 1
	UINT32 i;
	for(i=0; i<len; i++)
	{
		FIXED_PRINTF("0x%02x, ", *(data+i));
		if((i+1)%16==0)
			FIXED_PRINTF("\n");
	}
	if(i%16!=0)
		FIXED_PRINTF("\n");
#endif
}

#ifdef _HW_SECURITY_ENABLE_
/*
* Parameter:
* 	flag =1  main/see chunk head is wrong
*
*/
#ifndef LINUX_BOOTLOADER

static RET_CODE AppInit_OTA(UINT32 flag)
{
	UINT32 chid;
	UINT32 cpu_mc_len=0, see_mc_len=0, ota_len=0;
	BOOL run_second_loader = 0;
	static UINT8 *main_decrypted = NULL;
    static UINT8 *see_decrypted = NULL;
	UINT8 *main_entry;
    UINT32 block_addr = 0, block_len = 0;
    struct CRYPT_DATA_INFO crypt_data;
    struct SRAM_UKEY sram_ukey;
    struct CE_UKEY ce_ukey;
    struct UKEY_INFO *ukey = NULL;

    MG_Setup_CRC_Table();
	if( find_second_loader() != 1 )
		goto ret_err;

	FIXED_PRINTF("second loader code g_ota_offset=0x%x, flash_dev->totol_size=0x%x\n", g_ota_offset, flash_dev->totol_size);
	sto_chunk_init(g_ota_offset, flash_dev->totol_size - g_ota_offset);

    ukey = (struct UKEY_INFO *)MALLOC(sizeof(struct UKEY_INFO));
    if (NULL == ukey)
    {
        FIXED_PRINTF("Err, malloc buffer for ukey failed...\n");
        goto ret_err;
    }
    ukey->ce_ukey = &ce_ukey;
    ukey->sram_ukey = &sram_ukey;

    if(RET_SUCCESS != bl_prepare_key(ukey))
    {
        FIXED_PRINTF("prepare key fail!\n");
        goto ret_err;
    }

	FIXED_PRINTF ( "Run second loader main chunk id 0x%08x.\n", chid );
	chid = CHUNKID_SECLOADER;		
	block_len = 0;
	if ( RET_SUCCESS != cipher_get_chunk_len ( chid, &block_addr, &block_len ) )
	{
		FIXED_PRINTF ( "Can't find second loader chunk id 0x%08x.\n", chid );
		goto ret_err;
	}
	
	if(block_len == 0)
	{	
		FIXED_PRINTF ( "Can't find chunk id length 0x%08x.\n", chid );
		goto ret_err;		
	
	}
	main_decrypted = ( UINT8* ) ( 0xFFFFFFF8 & ( UINT32 ) MALLOC ( block_len + 0xf ) ) ;
    crypt_data.buf = NULL;
    crypt_data.blockid = 0;
    crypt_data.addr = block_addr;
    crypt_data.len = block_len;
    crypt_data.data_type = DATA_FROM_BLOCK_ADDR;
	if( RET_SUCCESS != aes_cbc_crypt(main_decrypted, &cpu_mc_len, &crypt_data, ukey, DSC_DECRYPT))
    {
		FIXED_PRINTF ( "Second loader decrypt failed\n");
		goto ret_err;
	}

	if ( ( cpu_mc_len == 0 ) || ( bl_unzip_sw ( ( UINT32 ) main_decrypted, cpu_mc_len,MAIN_CODE ) == 0 ) ){
		FIXED_PRINTF ( "Main code unzip error,goto reboot...\n" );
		goto ret_err;
	}

	if(RET_SUCCESS !=bl_sync_see_idle(NULL)){
		FIXED_PRINTF( "second loader sync see status failed\n" );
	    goto ret_err;
	}

	FIXED_PRINTF ( "Run second loader see chunk id 0x%08x.\n", chid );
	chid = CHUNKID_SECSEECODE;
	block_len = 0;   
	
	if ( RET_SUCCESS != cipher_get_chunk_len ( chid, &block_addr, &block_len ) )
	{
	    FIXED_PRINTF ( "Can't find second see loader chunk id 0x%08x.\n", chid );
		goto ret_err;
	}
	
	if(block_len == 0){
		FIXED_PRINTF ( "Can't find chunk id length 0x%08x.\n", chid );
		goto ret_err;		

	}	
	
	see_decrypted = ( UINT8* )  ( 0xFFFFFFF8 & ( UINT32 ) MALLOC ( block_len + 0xf ) );
	if( !see_decrypted )
	{
		FIXED_PRINTF("out of memory\n");
		goto ret_err;
	}
	if (RET_SUCCESS !=cipher_get_chunk_loading(chid,see_decrypted,block_addr,block_len))
	{
		FIXED_PRINTF ( "second loader see code load failed\n" );
	    goto ret_err;
	}
	set_see_code_info(see_decrypted,block_len,SEE_ENTRY);
	set_see_sig_info((UINT32)see_decrypted+block_len-SIG_LEN, SIG_LEN, RSASSA_PKCS1_V1_5);
    flush_ukey(ukey);
    set_see_key_info((UINT32)ukey | 0xa0000000);

	if(RET_SUCCESS != bl_verify_SW_see(DUVS_SEE)){
	    FIXED_PRINTF( "second loader see software trig failed\n" );
	    goto ret_err;
	}                       	

	if(RET_SUCCESS != bl_run_SW_see_later(NULL)){
		FIXED_PRINTF ( "see software run failed, sys will goto reboot ...\n"); 
		goto ret_err;
	}
	
	main_entry = MAIN_ENTRY ;
	if( RET_SUCCESS != bl_enter_sys_sw(NULL,NULL,main_entry,unzip_length))
	{
		FIXED_PRINTF("bl enter sys_sw failed , goto reboot\n");  
		goto ret_err;
	}
	
	return RET_SUCCESS;
	
 ret_err:
	return !RET_SUCCESS ;

}

#endif

void AppInit(void)
{
    UINT8  ch, *t1, *t2, i;    
    UINT32 boot_tick,chid;    
	UINT32 decrypt_flag = 0xff;
    UINT32 offset;
	UINT32 cpu_mc_len=0, see_mc_len=0;
    UINT8 *main_entry,*see_entry,*see_ram_address;
    static UINT8 *main_encrypted = NULL;
    static UINT8 *main_decrypted = NULL;
    static UINT8 *see_decrypted = NULL;
    UINT32 block_addr = 0, block_len = 0;
    UINT8  boot_type;
    UINT32 boot_code,tmp,data;
    UINT8 *temp_buffer = NULL;
	UINT8 *p;
	UINT8 sys_sw_wrong = 0;
    CHUNK_HEADER chunk_hdr;
	UINT32 fail_type = 0;
    struct CRYPT_DATA_INFO crypt_data;
    struct SRAM_UKEY sram_ukey;
    struct CE_UKEY ce_ukey;
    struct UKEY_INFO *ukey = NULL;

    sys_uart_init();      
	otp_init(NULL);

#ifdef M3515_SECURE_BOOT_ENABLE
	#ifdef LINUX_BOOTLOADER
		bl_trig_BL_see(__SEE_ROM_START,(__SEE_ROM_END - __SEE_ROM_START),SEE_ENTRY);
	#else
    	bl_trig_BL_see(__SEE_ROM_START,(__SEE_ROM_END - __SEE_ROM_START),SEE_ENTRY+0x1000000);   
	#endif
#else
	temp_buffer = (UINT8*)(0xFFFFFFF8&(UINT32)MALLOC(__SEE_ROM_END - __SEE_ROM_START+0xf));    
    /* Copy Mini See */
	MEMCPY((UINT8 *)(temp_buffer), __SEE_ROM_START, (__SEE_ROM_END - __SEE_ROM_START));
    osal_cache_flush(temp_buffer,(__SEE_ROM_END - __SEE_ROM_START));
	//See Self boot 
	self_boot(SEE_ENTRY, temp_buffer, (__SEE_ROM_END - __SEE_ROM_START), SEE_ENTRY);
    FREE(temp_buffer);
#endif

    g_boot_type = sys_ic_get_boot_type();
    FIXED_PRINTF("g_boot_type = %d\n", g_boot_type);

    if(g_boot_type != 1){
    	boot_code = *(UINT32 *)(0xA0000110);
    	/* Cold bootup */
    	boot_type = *(UINT8 *)(SYS_FLASH_BASE_ADDR + HW_SET_BOOTTYPE);
    FIXED_PRINTF("boot_type = %d\n", boot_type);
    FIXED_PRINTF("boot_code = 0x%x\n", boot_code);
#ifndef _PMU_STANDBY_ENABLE_        
    	if ((boot_type & BOOT_TYPE_MASK) && boot_code == 0xdead3bee)
    	{
    	    /* If cold bootup and enter standby enabled, enter standby */
    		sys_ic_enter_standby(0, 0);
    	}
#else
    /* If cold bootup and pmu enter standby enabled, enter pmu standby mode*/ 
    Cold_Pmu_Enter_Standby(boot_type);                 
#endif
    }else{
        /*transfer S5 and S7 to 220 for linux reboot get timer*/
        //if(boot_type == 0xdead1bee)
        {
          *(UINT32 *)(0xA0000220) = *(UINT32 *)(0xA0000110);
          *(UINT32 *)(0xA0000224) = *(UINT32 *)(0xA0000114);
          *(UINT32 *)(0xA0000228) = *(UINT32 *)(0xA0000118);
        }
    }

	/************       Initialize      ***********************/

#ifndef _LINUX_BOOTLOADER_	
    sys_gpio_init();
    sys_panel_init();
    panel_dev = (struct pan_device *)dev_get_by_id(HLD_DEV_TYPE_PAN, 0);
    pan_display(panel_dev, " ON ", 4);
#endif
    bl_init_flash();

#if 0
    vpo_dev_attach();
    vdec_dev_attach();
    avInit();
    avStart();
    api_show_bootup_logo();
    hdmi_show_on_bootloader(&LlvS);	
#endif

	dsc_api_attach();
	ce_api_attach();	
	see_step1();

    ukey = (struct UKEY_INFO *)MALLOC(sizeof(struct UKEY_INFO));
    if (NULL == ukey)
    {
        FIXED_PRINTF("Err, malloc buffer for ukey failed...\n");
        goto bl_reboot;
    }
    ukey->ce_ukey = &ce_ukey;
    ukey->sram_ukey = &sram_ukey;

    if(RET_SUCCESS != bl_prepare_key(ukey))
    {
        FIXED_PRINTF("prepare key fail!\n");
        goto bl_reboot;
    }

#ifndef LINUX_BOOTLOADER
	if(RET_SUCCESS != set_parameter_from_bl(0, NULL))
	{
		FIXED_PRINTF("prepare key fail!\n");
        goto bl_reboot;
	}
#endif	

	/* main sw decrypt */
	{
        #ifndef _LINUX_BOOTLOADER_	
            chid = CHUNKID_MAINCODE;
            block_len = 0;  

            if ( RET_SUCCESS != cipher_get_chunk_len ( chid, &block_addr, &block_len ) )
            {
                FIXED_PRINTF ( "Can't find chunk id 0x%08x.\n", chid );
				fail_type = 1;	
    			goto bl_ota;
            }
			
    		if(block_len == 0){
				FIXED_PRINTF ( "Can't find chunk id length 0x%08x.\n", chid );
				fail_type = 1;	
    			goto bl_ota;			 
    		}

			main_decrypted = ( UINT8* ) ( 0xFFFFFFF8 & ( UINT32 ) MALLOC ( block_len + 0xf ) ) ;

            crypt_data.buf = NULL;
            crypt_data.blockid = 0;
            crypt_data.addr = block_addr;
            crypt_data.len = block_len;
            crypt_data.data_type = DATA_FROM_BLOCK_ADDR;
			if( RET_SUCCESS != aes_cbc_crypt(main_decrypted, &cpu_mc_len, &crypt_data, ukey, DSC_DECRYPT))
            {
				FIXED_PRINTF(" main code decrypt failed\n");	
				goto bl_ota;
			}
        #else
            if (bl_get_uboot_addr(g_boot_type, &chid) != RET_SUCCESS)
            {
        		FIXED_PRINTF("Can't get uboot address.\n");
                sys_sw_wrong = 1;
    			goto bl_reboot;
            }
            block_len = 0;  

            if (g_boot_type != 1)
            {
                if ( RET_SUCCESS != cipher_get_chunk_len ( chid, &block_addr, &block_len ) )
                {
                    FIXED_PRINTF ( "Can't find chunk id 0x%08x.\n", chid );
        			goto bl_reboot;
                }
        
				if(block_len == 0)
				{	
					FIXED_PRINTF ( "Can't find chunk id length 0x%08x.\n", chid );
					goto bl_reboot;		
				
				}

				main_decrypted = (UINT8 *)(0xFFFFFFF8 & (UINT32)MALLOC(block_len + 0xf));

                crypt_data.buf = NULL;
                crypt_data.blockid = 0;
                crypt_data.addr = block_addr;
                crypt_data.len = block_len;
                crypt_data.data_type = DATA_FROM_BLOCK_ADDR;
    			if( RET_SUCCESS != aes_cbc_crypt(main_decrypted, &cpu_mc_len, &crypt_data, ukey, DSC_DECRYPT))
                {
    				FIXED_PRINTF(" main code decrypt failed\n");	
				    goto bl_reboot;		
    			}     		
        		
            }
        else
        {
            #ifndef _NAND_WITHOUT_PMI_
                FIXED_PRINTF("Load uboot:\n");
                cpu_mc_len = g_nand_info.uboot_len;
                main_encrypted = (UINT8*)(0xFFFFFFF8&(UINT32)MALLOC(cpu_mc_len+0xf));
                if (api_load_data_from_nandflash(chid, cpu_mc_len, main_encrypted) != 0)
                {
                    FIXED_PRINTF("Load uboot fail...\n");
                    goto bl_reboot;
                }
                main_decrypted = (UINT8*)(0xFFFFFFF8&(UINT32)MALLOC(cpu_mc_len+0xf));

                //decrypt uboot code
                crypt_data.buf = main_encrypted;
                crypt_data.blockid = 0;
                crypt_data.addr = 0;
                crypt_data.len = 0;
                crypt_data.data_type = DATA_FROM_SRAM;
    			if( RET_SUCCESS != aes_cbc_crypt(main_decrypted, &cpu_mc_len, &crypt_data, ukey, DSC_DECRYPT))
                {
    				FIXED_PRINTF(" main code decrypt failed\n");	
    				goto bl_reboot;
    			}
                free(main_encrypted);
            #else
				FIXED_PRINTF ( "Unsupported boot type.\n" );
				goto bl_reboot;	
            #endif
            }
        #endif
	}

	/* SEE sw decrypt & verify */
	{
		chid = CHUNKID_SEECODE;
        block_len = 0;   
	    #ifndef LINUX_BOOTLOADER 
	        if ( RET_SUCCESS != cipher_get_chunk_len ( chid, &block_addr, &block_len ) )
	        {
                FIXED_PRINTF ( "Can't find chunk id 0x%08x.\n", chid );
				fail_type = 1;	
                goto bl_ota;
	        }

			if(block_len == 0)
			{	
				FIXED_PRINTF ( "Can't find chunk id length 0x%08x.\n", chid );
				fail_type = 1;	
                goto bl_ota;

			}
				                          
            see_decrypted = ( UINT8* )  ( 0xFFFFFFF8 & ( UINT32 ) MALLOC ( block_len + 0xf ) ) ;
            if (RET_SUCCESS !=cipher_get_chunk_loading(chid,see_decrypted,block_addr,block_len))
			{
				FIXED_PRINTF ( "bootloader see code load failed\n" );
				fail_type = 1;	
                goto bl_ota;
			}
            set_see_code_info(see_decrypted,block_len,SEE_ENTRY);
            set_see_sig_info((UINT32)see_decrypted+block_len-SIG_LEN, SIG_LEN, RSASSA_PKCS1_V1_5);
            flush_ukey(ukey);
            set_see_key_info((UINT32)ukey | 0xa0000000);
            if(RET_SUCCESS != bl_verify_SW_see(DUVS_SEE)){
                FIXED_PRINTF( "bootloader see software trig failed\n" );
                goto bl_ota;
            }                       

		#endif
		#ifndef LINUX_BOOTLOADER
			if ((cpu_mc_len == 0) || (bl_unzip_sw((UINT32)main_decrypted, cpu_mc_len, MAIN_CODE) == 0)){
	                FIXED_PRINTF ( "Main code unzip error\n" );	
	                goto bl_ota;;
	        }	
			main_entry= MAIN_ENTRY;
	    #else
	         memcpy ( MAIN_ENTRY,( UINT32 ) main_decrypted, cpu_mc_len);
	         osal_cache_flush(MAIN_ENTRY,cpu_mc_len);
			 main_entry= MAIN_ENTRY;
	         unzip_length = cpu_mc_len ;
	    #endif
	}
	
	/* main sw verify */
	{
	#ifdef LINUX_BOOTLOADER 		
		if( version_check((UINT32)CHUNKID_UBOOT,(UINT32)main_entry,unzip_length) != 0){
		 FIXED_PRINTF("main software version check failed\n");
			goto bl_reboot;
		}   
	#else
		if( version_check((UINT32)CHUNKID_FW,(UINT32)main_entry,unzip_length) != 0){
		 	FIXED_PRINTF("main software version check failed\n");
			goto bl_ota;
		}
	#endif
		if((unzip_length == 0)||( Test_RSA_Ram ( ( UINT32 ) main_entry, unzip_length ) != 0 ) ){
			FIXED_PRINTF ( "main software verify failed, sys will goto reboot ...\n" );
			goto bl_ota;
		}
		#ifdef LINUX_BOOTLOADER
			set_uboot_config(main_entry) ;
		#endif
	}
	
	#ifndef LINUX_BOOTLOADER
	    if(RET_SUCCESS != bl_run_SW_see_later(NULL)){
			FIXED_PRINTF ( "see software run failed, sys will goto reboot ...\n"); 
			goto bl_ota;
		}
	#endif
  
 	if( RET_SUCCESS != bl_enter_sys_sw(NULL,NULL,main_entry,unzip_length))
	{
		FIXED_PRINTF("bl enter sys_sw failed , goto reboot\n");  
		goto bl_reboot;
	}
	
bl_ota:

#if (!defined LINUX_BOOTLOADER)&&(defined _OTA_E_)	
	if( RET_SUCCESS !=AppInit_OTA(fail_type) )	
	{
		FIXED_PRINTF("ota flow failed, goto reboot\n");  
		goto bl_reboot;
	}		
#endif
bl_reboot:  
      FIXED_PRINTF("Bootloader reboot\n");  
      hw_watchdog_reboot();  
}

/*retailer or sw CA flow*/
#else
void AppInit(void)
{
    UINT8  ch, *t1, *t2, i;    
    UINT32 boot_tick,chid,bl_uk_offset;    
    UINT32 decrypt_flag = 0xff;
    UINT32 offset,offset1=0,offset2=0;
    UINT32 cpu_mc_len=0, see_mc_len=0, ota_len=0;
    UINT8 *main_entry,*see_entry,*see_ram_address;       
    UINT32 block_addr = 0, block_len = 0;
    UINT8  boot_type, flash_speed;
    UINT32 boot_code,tmp,data;
    UINT8 *main_buff = NULL;
    UINT8 *see_buff = NULL;
    UINT8 *ota_buff = NULL;
    UINT8 *logo_buff = NULL;
    UINT8 *temp_buffer = NULL;
    UINT32 ziped_len = 0;
    UINT8 *p;
    UINT8 sys_sw_wrong = 0;
    UINT32 see_unzip_length = 0;	
    CHUNK_HEADER chunk_hdr;  

#ifdef DUAL_ENABLE
	temp_buffer = (UINT8*)(0xFFFFFFF8&(UINT32)MALLOC(__SEE_ROM_END - __SEE_ROM_START+0xf));    
    /* Copy Mini See */
	MEMCPY((UINT8 *)(temp_buffer), __SEE_ROM_START, (__SEE_ROM_END - __SEE_ROM_START));
    osal_cache_flush(temp_buffer,(__SEE_ROM_END - __SEE_ROM_START));
	//See Self boot 
	self_boot(BL_SEE_ENTRY, temp_buffer, (__SEE_ROM_END - __SEE_ROM_START), BL_SEE_ENTRY);
    FREE(temp_buffer);
#endif

#ifdef CI_PLUS_SUPPORT
	UINT32 maincode_len, maincode_addr, len_left;
	UINT8 maincode_left[32];
#endif

	/************       Initialize      ***********************/ 
    sys_uart_init();
    FIXED_PRINTF("HW BootLoader APP  init!\n");
#ifndef _LINUX_BOOTLOADER_	
    sys_gpio_init();
    sys_panel_init();
    panel_dev = (struct pan_device *)dev_get_by_id(HLD_DEV_TYPE_PAN, 0);
    pan_display(panel_dev, " ON ", 4);
#endif

#ifdef _MPLOADER_ENABLE_
	FIXED_PRINTF("Mp loader begin to run\n");
	if( RET_SUCCESS != MpApp())
	{
		FIXED_PRINTF("Mp Application run failed\n");
		goto bl_reboot;
	}
#endif

	g_boot_type = sys_ic_get_boot_type();
	FIXED_PRINTF("g_boot_type = %d\n", g_boot_type);
	bl_init_flash();

	if(g_boot_type != 1)
	{
		boot_code = *(UINT32 *)(0xA0000110);
		/* Cold bootup */
		boot_type = *(UINT8 *)(SYS_FLASH_BASE_ADDR + HW_SET_BOOTTYPE);
		FIXED_PRINTF("boot_type = %d\n", boot_type);
		FIXED_PRINTF("boot_code = 0x%x\n", boot_code);
#ifndef _PMU_STANDBY_ENABLE_        
		if((boot_type & BOOT_TYPE_MASK) && boot_code == 0xdead3bee)
		{
			/* If cold bootup and enter standby enabled, enter standby */
			sys_ic_enter_standby(0, 0);
		}
#else
		/* If cold bootup and pmu enter standby enabled, enter pmu standby mode*/ 
		Cold_Pmu_Enter_Standby(boot_type);                 
#endif
	}
	else
	{
		/*transfer S5 and S7 to 220 for linux reboot get timer*/
		//if(boot_type == 0xdead1bee)
		{
			*(UINT32 *)(0xA0000220) = *(UINT32 *)(0xA0000110);
			*(UINT32 *)(0xA0000224) = *(UINT32 *)(0xA0000114);
			*(UINT32 *)(0xA0000228) = *(UINT32 *)(0xA0000118);
		}
	}

	MG_Setup_CRC_Table();
	FIXED_PRINTF("MG_Setup_CRC_Table finish.\n");
	g_crc_bad = check_program();
	FIXED_PRINTF("check_program finish.\n"); 

#ifdef DUAL_CPU
	see_ram_address = bl_config_memory(NULL,NULL);
#endif

#if (defined _BOOT_LOGO_) || (defined _BOOT_AV_)
#ifdef _BOOT_AV_
    chid = CHUNKID_AV;
#else
    chid = CHUNKID_LOGO;
#endif
    block_len = 0;  
	if(RET_FAILURE == bl_get_chunk_len(chid, &block_addr, &block_len))
	{
		FIXED_PRINTF("Can't find chunk id 0x%08x.\n", chid);
        sys_sw_wrong = 1;
		goto bl_reboot;
	}
    else if(block_len == 0)
    {
	    sys_sw_wrong = 1;
		FIXED_PRINTF("logo len is zero.\n");
		goto bl_reboot;
    }
    logo_buff = (UINT8*)(0xFFFFFFF8&(UINT32)MALLOC(block_len+0xf));             	
	sto_get_data(flash_dev, logo_buff, block_addr, block_len);
	FIXED_PRINTF("load logo, %x, %x, %x.\n", logo_buff, block_len, chid);

 
#ifdef _BOOT_AV_
    bl_show_av(logo_buff, block_len);
#else
    bl_show_logo(logo_buff, block_len);
#endif
#endif

#ifdef CI_PLUS_SUPPORT
	/*RSA verify maincode*/
	FIXED_PRINTF("start RSA verify maincode.\n");
	struct sto_device *dev = (struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0);

	chid = 0x01FE0101;
	maincode_addr = sto_chunk_goto(&chid, 0xFFFFFFFF, 1);
	maincode_len = sto_fetch_long(maincode_addr + CHUNK_LENGTH);
	maincode_addr = maincode_addr + CHUNK_HEADER_SIZE;
	maincode_len = maincode_len - CHUNK_HEADER_SIZE;
	sto_get_data(dev, maincode_left, maincode_addr+maincode_len, 32);
	for (len_left = 0; maincode_left[len_left] != 0xff; len_left++);
	if(0 == maincode_verify(maincode_addr, maincode_len+len_left))
	{
		FIXED_PRINTF("maincode verify success.\n");
	}
	else
	{
		FIXED_PRINTF("maincode verify failed.\n");
		return;
	}
#endif

    if (g_crc_bad == 0)
    {
        /* If dynamic application load enable, try load this application */
        if (boot_code == 0xdead2bee)
        {
            chid = *((UINT32 *)0xA0000114);
            offset = sto_chunk_goto(&chid, *((UINT32 *)0xA0000118), 1);
        }else{
            /*load main software or uboot*/ 
#ifndef _LINUX_BOOTLOADER_	
            chid = CHUNKID_MAINCODE;
#else
            if (bl_get_uboot_addr(g_boot_type, &chid) != RET_SUCCESS)
            {
        		FIXED_PRINTF("Can't get uboot address.\n");
                sys_sw_wrong = 1;
    			goto bl_reboot;
            }
#endif

    		#ifndef	_NAND_BOOT_E_
    	        block_len = 0;  
    	    	if(RET_FAILURE == bl_get_chunk_len(chid, &block_addr, &block_len))
    	    	{
    	    		FIXED_PRINTF("Can't find chunk id 0x%08x.\n", chid);
    	            sys_sw_wrong = 1;
    				goto bl_reboot;
    	    	}
    	        else if(block_len != 0)
    	        {
    	            main_buff = (UINT8*)(0xFFFFFFF8&(UINT32)MALLOC(block_len+0xf));             	
    	        	sto_get_data(flash_dev, main_buff, block_addr, block_len);
    	            cpu_mc_len = block_len;
    	        	FIXED_PRINTF("CPU Main code, %x, %x, %x, %x.\n", main_buff, block_len, chid, cpu_mc_len);
    				#ifdef _LINUX_BOOTLOADER_
    					main_entry = (UINT8*)MAIN_ENTRY;	
    					memcpy(main_entry,main_buff,cpu_mc_len);
    					osal_cache_flush(main_entry,cpu_mc_len);
    				#endif
    	        }        
    	        else
    	    	{
    	    	    sys_sw_wrong = 1;
    	    		FIXED_PRINTF("maincode len is zero.\n");
    				goto bl_reboot;
    	    	}
    		#else
    			FIXED_PRINTF("Load uboot:\n");
                main_entry = (UINT8*)MAIN_ENTRY;
                if (api_load_data_from_nandflash(chid, g_nand_info.uboot_len, main_entry) != 0)
                {
                    FIXED_PRINTF("Load uboot fail...\n");
                    goto bl_reboot;
                }
    		#endif
        }
	
#if (defined DUAL_CPU) && (!defined _LINUX_BOOTLOADER_) 
        chid = CHUNKID_SEECODE;
        block_len = 0;    

    	if(RET_FAILURE == bl_get_chunk_len(chid, &block_addr, &block_len))
    	{
    		FIXED_PRINTF("Can't find chunk id 0x%08x.\n", chid);
    		sys_sw_wrong = 1;
    		goto bl_reboot;
    	}
        else if(block_len != 0)
        {
            see_buff = (UINT8*)(0xFFFFFFF8&(UINT32)MALLOC(block_len+0xf));
        	
        	sto_get_data(flash_dev, see_buff, block_addr, block_len);
            see_mc_len = block_len;
            FIXED_PRINTF("SEE Main code, %x, %x, %x, %x.\n", see_buff, block_len, chid, see_mc_len);        

            //for decompress use.
            g_see_unziped = (UINT8*)(0xFFFFFFF8&(UINT32)MALLOC(block_len*4));
        }               
        else
    	{
    	    sys_sw_wrong = 1;
    		FIXED_PRINTF("seecode len is zero.\n");
    		goto bl_reboot;
    	}
#endif
    }
#if (defined _OTA_E_) &&(!defined _LINUX_BOOTLOADER_)
    else if (find_second_loader() == 1) /* ota.bin */
    {
        /* loader the main code */
	    block_len = sto_fetch_long(g_ota_offset + CHUNK_LENGTH) - CHUNK_HEADER_SIZE + CHUNK_NAME;
        if (block_len != 0)
        {
            main_buff = (UINT8*)(0xFFFFFFF8&(UINT32)MALLOC(block_len+0xf));
            sto_get_data(flash_dev, main_buff, (g_ota_offset + CHUNK_HEADER_SIZE), block_len);
            FIXED_PRINTF("\nMain code, %x, %x, %x.\n", main_buff, block_len, CHUNKID_SECLOADER);
        }
        else
    	{
    	    sys_sw_wrong = 1;
    		FIXED_PRINTF("maincode len is zero.\n");
            goto bl_reboot;
    	}
#if (defined DUAL_CPU) &&(!defined _LINUX_BOOTLOADER_) 
        if(sys_sw_wrong != 1)
        {
            /* loader the see code */
            sto_chunk_init(g_ota_offset, flash_dev->totol_size - g_ota_offset);

            chid = CHUNKID_SECSEECODE;
            block_len = 0;  //get the block_len
        	if(RET_FAILURE == bl_get_chunk_len(chid, &block_addr, &block_len))
        	{
        		FIXED_PRINTF("Can't find chunk id 0x%08x.\n", chid);
        		sys_sw_wrong = 1;
                goto bl_reboot;
        	}
            else if(block_len != 0)
            {
                see_buff = (UINT8*)(0xFFFFFFF8&(UINT32)MALLOC(block_len+0xf));
            	//aes_cbc_decrypt_chunk(pos, CHUNKID_SEECODE, see_decrypted, &see_mc_len);
            	sto_get_data(flash_dev, see_buff, block_addr, block_len);
                FIXED_PRINTF("\nSEE Main code, %x, %x, %x, %x.\n", see_buff, block_len, chid, see_mc_len);        

                //for decompress use.
                g_see_unziped = (UINT8*)(0xFFFFFFF8&(UINT32)MALLOC(block_len*4));
            }
            else
        	{
        	    sys_sw_wrong = 1;
        		FIXED_PRINTF("seecode len is zero.\n");
                goto bl_reboot;
        	}

            sto_chunk_init(0, flash_dev->totol_size);
        }
#endif
    }
#endif
    else
    {
        FIXED_PRINTF("crc bad and no secloader!\n");
        goto bl_reboot;
    }
	
#if (defined DUAL_CPU) &&(!defined _LINUX_BOOTLOADER_)
	see_entry = 0;
	p = see_buff+(see_mc_len-0x200);
	ziped_len = p[3]|(p[2] << 8) |(p[1] << 16)|(p[0] << 24);
	//enter Maincode
	FIXED_PRINTF("expand see main code, ziped len: 0x%x\n", ziped_len);
	#ifdef LZO_COMPRESS_ENABLE
	    see_entry = expand_ram(see_buff, ziped_len, unlzo, SEE_CODE);
	#else
	    see_entry = expand_ram(see_buff, ziped_len, un7zip, SEE_CODE);
	#endif
    see_unzip_length = unzip_length;
    FIXED_PRINTF("expand see, unzip_length = 0x%x\n", unzip_length);

    if (see_entry != 0)
    {
        osal_cache_flush((UINT32)see_entry, unzip_length);

#ifndef DUAL_ENABLE
    	FIXED_PRINTF("run see, see_entry = 0x%x!\n", see_entry);            	 	

    	see_boot_init(see_entry, unzip_length,see_ram_address);
    	see_boot_ex();
    	//wait for see copy finish
    	wait_see_done();
#endif    
    }
    else
    {
        sys_sw_wrong = 1;
        FIXED_PRINTF("expand see error, see_entry = 0x%x!\n", see_entry);
		goto bl_reboot;
    }
#endif    

	#ifndef _LINUX_BOOTLOADER_
		main_entry = 0;   	
    	p = main_buff+(cpu_mc_len-0x200);
    	ziped_len = p[3]|(p[2] << 8) |(p[1] << 16)|(p[0] << 24);
    	FIXED_PRINTF("expand cpu main code, ziped len: 0x%x\n", ziped_len);

        #ifdef LZO_COMPRESS_ENABLE
    	    main_entry = expand_ram(main_buff, ziped_len, unlzo, MAIN_CODE);
        #else
    	    main_entry = expand_ram(main_buff, ziped_len, un7zip, MAIN_CODE);
        #endif

		if(main_entry != 0)
		{
	        boot_tick = read_tsc();
	        do
	        {
	            if (sci_read_tm(SCI_FOR_RS232, &ch, 5) == SUCCESS && ch == 'c')
	                break;
	            else
	                ch = 0;
	        }
	        while (read_tsc() - boot_tick < WAIT_300MS);

#ifdef _BOOT_LOGO_
            // Wait Media play over
            boot_tick = read_tsc();
            do
            {
                if (check_videologo_playback_status())
                {
                    break;
                }
            }while(read_tsc() - boot_tick < LOGO_DELAY);
#endif

	        if (ch != 'c')
	        {
	            set_os_config(128,64,64,64,64);
                osal_cache_flush(main_entry, unzip_length);
                FIXED_PRINTF("expand main, unzip_length = 0x%x\n", unzip_length);
#ifdef DUAL_CPU
#ifdef DUAL_ENABLE
                self_boot(SEE_ENTRY, see_entry, see_unzip_length, 0);
#else
                FIXED_PRINTF("4!\n");
                bl_see_boot(see_ram_address);
#endif //DUAL_ENABLE
#else
#ifdef DUAL_ENABLE
                reset_see();
                close_see();
#endif
#endif //DUAL_CPU
	        	FIXED_PRINTF("success!\n");
	            set_see_boot_flag();
	            hw_watchdog_stop();
	            exec(main_entry);
	        }

	    	lib_ash_shell();	
		}
	#else		        
        FIXED_PRINTF ( "jump to fw entry=%x\n", main_entry );
        hw_watchdog_stop();
        osal_cache_flush(main_entry,0x800000);        
        exec ( main_entry );	
	#endif

bl_reboot:  
      FIXED_PRINTF("Bootloader fail\n");  
      SDBBP();
}
#endif

